﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace vm.Aspects.Policies.Tests
{
    public class MethodInvocationMock : IMethodInvocation
    {
        object _target;
        MethodBase _method;

        public MethodInvocationMock(
            object target,
            MethodBase method,
            IParameterCollection parameters)
        {
            _target = target;
            _method = method;
            Inputs  = parameters;
        }

        #region IMethodInvocation Members

        public IParameterCollection Arguments
        {
            get
            {
                return new ParameterCollection(new object[0], new ParameterInfo[0], p => true);
            }
        }

        public IMethodReturn CreateExceptionMethodReturn(
            Exception ex)
        {
            return new MethodReturnMock
            {
                Exception = ex,
            };
        }

        public IMethodReturn CreateMethodReturn(
            object returnValue,
            params object[] outputs)
        {
            return new MethodReturnMock
            {
                ReturnValue = returnValue,
            };
        }

        public IParameterCollection Inputs { get; set; }

        public IDictionary<string, object> InvocationContext
        {
            get { throw new NotImplementedException(); }
        }

        public MethodBase MethodBase
        {
            get { return _method; }
        }

        public object Target
        {
            get { return _target; }
        }

        #endregion

        public int TimesNextCalled { get; set; }

        public IMethodReturn InvokeNext(IMethodInvocation invocation, GetNextHandlerDelegate getNext)
        {
            TimesNextCalled++;

            var parameters = new object[invocation.Inputs.Count];

            for (var i=0; i<parameters.Length; i++)
                parameters[i] = invocation.Inputs[i];

            try
            {
                return new MethodReturnMock
                {
                    ReturnValue = invocation.MethodBase.Invoke(
                                    invocation.Target,
                                    parameters),
                };
            }
            catch (Exception x)
            {
                return new MethodReturnMock
                {
                    Exception = x,
                };
            }
        }
    }
}
